# 消息的数据结构：
# 1. 消息UUID
# 2. deviceID
# 3. 是不是我的服务器
# 4. 用户接受者ID
# 5. 用户发送者ID
# 6. 消息
# 7. 消息类型
# 8. 消息时间
# 9. 消息体


# 用户的数据结构
# 1. 用户UUID
# 2. 用户密钥
# 3. 用户名称
# 4. 用户头像
# 5. 用户状态


# 场景：
# 1. 第一次探测：（手机发送）自己的信息，有可能有自己的消息发送，比如，已经读到了的消息id。（服务器返回）
# 2. 
# 3. 
# 4. 







# see origin link: https://RandomNerdTutorials.com/micropython-esp32-bluetooth-low-energy-ble/
from micropython import const
import asyncio
import aioble
import bluetooth
import struct
from machine import Pin
from random import randint
import binascii
import json
import math
import uasyncio as asyncio

# See the following for generating UUIDs:
# https://www.uuidgenerator.net/
_BLE_SERVICE_UUID = bluetooth.UUID("2d5baa90-35a1-4345-88bc-b8f84e0fcc63")
_BLE_META_CHAR_UUID = bluetooth.UUID("2d5baa91-35a1-4345-88bc-b8f84e0fcc63")
_BLE_DATA_CHAR_UUID = bluetooth.UUID('2d5baa92-35a1-4345-88bc-b8f84e0fcc63')
# How frequently to send advertising beacons.
_ADV_INTERVAL_MS = 250_000

PAGE_SIZE = 20 # 分包大小，单位为字节

# Register GATT server, the service and characteristics
ble_service = aioble.Service(_BLE_SERVICE_UUID)
meta_characteristic = aioble.Characteristic(ble_service, _BLE_META_CHAR_UUID, read=True, write=True, notify=True, capture=True)
data_characteristic = aioble.Characteristic(ble_service, _BLE_DATA_CHAR_UUID, read=True, write=True, notify=True, capture=True)

# Register service(s)
aioble.register_services(ble_service)

# 每次传输的chunks数量，用meta“特征”来传递。
meta_read_chunks_number = -1

# Converts a UTF-8 string to a hex-encoded Uint8Array.
# Args: text: The UTF-8 string to convert.
# Returns: A string representing the hex-encoded Uint8Array.
def utf8_string_to_hex_uint8array(text):
    utf8_bytes = text.encode('utf-8')
    hex_bytes = ''.join([f'{byte:02x}' for byte in utf8_bytes])
    return hex_bytes

# Converts a hex-encoded Uint8Array to a UTF-8 string.
# Helper to encode the data characteristic UTF-8
def _encode_data(data):
    return str(data).encode('utf-8')




# Serially wait for connections. Don't advertise while a central is connected.
async def peripheral_task():
    while True:
        try:
            async with await aioble.advertise(
                _ADV_INTERVAL_MS,
                name="TrueTalk",
                services=[_BLE_SERVICE_UUID],
                ) as connection:
                    print("Connection from", connection.device)
                    await connection.disconnected()             
        except asyncio.CancelledError:
            # Catch the CancelledError
            print("Peripheral task cancelled")
        except Exception as e:
            print("Error in peripheral_task:", e)
        finally:
            # Ensure the loop continues to the next iteration
            await asyncio.sleep_ms(100)


# Get new value and update characteristic
async def meta_task():
    
    global meta_read_chunks_number  # 声明要修改全局变量
    
    while True:
        try:
            connection, data = await meta_characteristic.written()
            hex_bytes = binascii.hexlify(data)
#           
            string_bytes = bytes.fromhex(hex_bytes)
            string_china = string_bytes.decode('utf-8', 'ignore')
            print("META CHAR utf8 = ", string_china)
            
            # meta信息只有一个内容，分为多少个chunk，设置两个数量。
            meta_read_chunks_number = int(string_china)
            

       
        except asyncio.CancelledError:
            # Catch the CancelledError
            print("meta task cancelled")
        except Exception as e:
            print("Error in meta_task:", e)
        finally:
            # Ensure the loop continues to the next iteration
            await asyncio.sleep_ms(100)

# 传输data的内容。
async def data_task():
    

    global meta_read_chunks_number  # 声明要修改全局变量


    print(meta_read_chunks_number)
    print(type(meta_read_chunks_number))
    
    mutable_bytearray = bytearray(b'')
    print("mutable_bytearray's type =", type(mutable_bytearray))
    while True:
        try:
            connection, data = await data_characteristic.written()
            hex_bytes = binascii.hexlify(data)
            string_bytes = bytes.fromhex(hex_bytes)
            # print("string_bytes's type =", type(string_bytes))
            # string_china = string_bytes.decode('utf-8', 'ignore')
            mutable_bytearray += string_bytes
            
            print("meta_read_chunks_number =", meta_read_chunks_number)
            
            if (meta_read_chunks_number > 1):
                
                # 计数 -1
                meta_read_chunks_number = meta_read_chunks_number - 1
            else:
                
                # 转换回 bytes（如需不可变对象）
                result_bytes = bytes(mutable_bytearray)

                string_china_total = result_bytes.decode('utf-8', 'ignore')
                print("DATA CHAR utf8 = ", string_china_total)
            
                # 做完以后，把所有的数据清零
                mutable_bytearray = bytearray(b'')
                meta_read_chunks_number = -1
                
                # 转化为json
                # 转换为字典
                json_dict = json.loads(string_china_total)
                print(json_dict["id"])
                print(json_dict["cmd"])

                return_json = reply(json_dict)
                # 转换为 JSON 字符串
                return_json_str = json.dumps(return_json)
                #return_json_str = "{\"id\":\"master\",\"text\":\"《贺新郎·读史》人猿相揖别。只几个石头磨过，小儿时节。铜铁炉中翻火焰，为问何时猜得，不过几千寒热。人世难逢开口笑，上疆场彼此弯弓月。流遍了，郊原血。一篇读罢头飞雪，但记得斑斑点点，几行陈迹。五帝三皇神圣事，骗了无涯过客。有多少风流人物？盗跖庄蹻流誉后，更陈王奋起挥黄钺。歌未竟，东方白。\"}"
    
                
                
                arraybuffer = _encode_data(return_json_str)
                bytesLength = len(arraybuffer)

                print(type(arraybuffer))
                print("bytesLength = ", bytesLength)

                meta_write_chunks_number = math.ceil(bytesLength / PAGE_SIZE)  # 先进行浮点数除法 7/3 ≈ 2.333，再向上取整得到 3
                print("str(meta_write_chunks_number)=", str(meta_write_chunks_number))
                
                meta_characteristic.write(_encode_data(str(meta_write_chunks_number)), send_update=True)
                
                print("meta_write_chunks_number =", meta_write_chunks_number)
                await asyncio.sleep(0.02)  # 避免发送过快
                # 标记点
                flag_pointer = 0

                while flag_pointer < bytesLength:
                        
                    next_flag_pointer = flag_pointer + PAGE_SIZE

                    print("--\n")
                    print(flag_pointer)
                    print(next_flag_pointer)

                    if next_flag_pointer < bytesLength:
                        chunk = arraybuffer[flag_pointer:next_flag_pointer]
                        print("chunk:", chunk)
                        data_characteristic.write(chunk, send_update=True)
                        await asyncio.sleep(0.02)  # 避免发送过快
                    else:
                        chunk = arraybuffer[flag_pointer:bytesLength]
                        print("chunk:", chunk)
                        data_characteristic.write(chunk, send_update=True)
                        
                    flag_pointer += PAGE_SIZE
                    print("flag_pointer = ", flag_pointer)
            
        except asyncio.CancelledError:
            # Catch the CancelledError
            print("data task cancelled")
        except Exception as e:
            print("Error in data_task:", e)
        finally:
            # Ensure the loop continues to the next iteration
            await asyncio.sleep_ms(100)

# 该系统的核心是应答模式，接收一段信息，回复一段信息。
def reply(json_dict):

    print(json_dict["id"])
    print(json_dict["cmd"])
    print(json_dict["text"])
    # 用户大概有

    # 假设现在有个信息，给写回去。
    # return_json = json.load(return_string)
    mao_text = "《贺新郎·读史》人猿相揖别。只几个石头磨过，小儿时节。铜铁炉中翻火焰，为问何时猜得，不过几千寒热。人世难逢开口笑，上疆场彼此弯弓月。流遍了，郊原血。一篇读罢头飞雪，但记得斑斑点点，几行陈迹。五帝三皇神圣事，骗了无涯过客。有多少风流人物？盗跖庄蹻流誉后，更陈王奋起挥黄钺。歌未竟，东方白。"
    return_json = {
        "id": "master",
        "text": mao_text
    }
    
    return return_json


# Run tasks
async def main():
    t1 = asyncio.create_task(meta_task())
    t2 = asyncio.create_task(peripheral_task())
    t3 = asyncio.create_task(data_task())
    await asyncio.gather(t1, t2, t3)
    
asyncio.run(main())


